home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-29  |  30.0 KB  |  1,405 lines

  1. /* 
  2.  *  Window Maker window manager
  3.  * 
  4.  *  Copyright (c) 1997, 1998 Alfredo K. Kojima
  5.  * 
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  19.  *  USA.
  20.  */
  21. #include "wconfig.h"
  22.  
  23. #include <X11/Xlib.h>
  24. #include <X11/Xutil.h>
  25. #include <X11/Xatom.h>
  26. #include <sys/stat.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <unistd.h>
  31. #include <stdarg.h>
  32. #include <pwd.h>
  33. #include <math.h>
  34. #include <time.h>
  35.  
  36. #include <WUtil.h>
  37. #include <wraster.h>
  38.  
  39.  
  40. #include "WindowMaker.h"
  41. #include "GNUstep.h"
  42. #include "screen.h"
  43. #include "wcore.h"
  44. #include "window.h"
  45. #include "framewin.h"
  46. #include "funcs.h"
  47. #include "defaults.h"
  48. #include "dialog.h"
  49. #include "xutil.h"
  50. #include "xmodifier.h"
  51.  
  52.  
  53. /**** global variables *****/
  54.  
  55. extern char *DisplayName;
  56.  
  57. extern WPreferences wPreferences;
  58.  
  59. extern Time LastTimestamp;
  60.  
  61. #ifdef OFFIX_DND
  62. extern Atom _XA_DND_SELECTION;
  63. #endif
  64.  
  65.  
  66. #ifdef USECPP
  67. static void
  68. putdef(char *line, char *name, char *value)
  69. {
  70.     if (!value) {
  71.     wwarning(_("could not define value for %s for cpp"), name);
  72.     return;
  73.     }
  74.     strcat(line, name);
  75.     strcat(line, value);
  76. }
  77.  
  78.  
  79.  
  80. static void
  81. putidef(char *line, char *name, int value)
  82. {
  83.     char tmp[64];
  84.     sprintf(tmp, "%i", value);
  85.     strcat(line, name);
  86.     strcat(line, tmp);
  87. }
  88.  
  89.  
  90. static char*
  91. username()
  92. {
  93.     char *tmp;
  94.     
  95.     tmp = getlogin();
  96.     if (!tmp) {
  97.     struct passwd *user;
  98.  
  99.     user = getpwuid(getuid());
  100.     if (!user) {
  101.         wsyserror(_("could not get password entry for UID %i"), getuid());
  102.         return NULL;
  103.     }
  104.     if (!user->pw_name) {
  105.         return NULL;
  106.     } else {
  107.         return user->pw_name;
  108.     }
  109.     }
  110.     return tmp;
  111. }
  112.        
  113. char *
  114. MakeCPPArgs(char *path)
  115. {
  116.     int i;
  117.     char buffer[MAXLINE], *buf, *line;
  118.     Visual *visual;
  119.     char *tmp;
  120.     
  121.     line = wmalloc(MAXLINE);
  122.     *line = 0;
  123.     i=1;
  124.     if ((buf=getenv("HOSTNAME"))!=NULL) {
  125.     if (buf[0]=='(') {
  126.         wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"),
  127.              buf);
  128.     } else 
  129.       putdef(line, " -DHOST=", buf);
  130.     } else if ((buf=getenv("HOST"))!=NULL) {
  131.     if (buf[0]=='(') {
  132.         wwarning(_("your machine is misconfigured. HOST is set to %s"),
  133.              buf);
  134.     } else 
  135.       putdef(line, " -DHOST=", buf);
  136.     }
  137.     buf = username();
  138.     if (buf)
  139.       putdef(line, " -DUSER=", buf);
  140.     putidef(line, " -DUID=", getuid());
  141.     buf = XDisplayName(DisplayString(dpy));
  142.     putdef(line, " -DDISPLAY=", buf);
  143.     putdef(line, " -DWM_VERSION=", VERSION);
  144.     
  145.     visual = DefaultVisual(dpy, DefaultScreen(dpy));
  146.     putidef(line, " -DVISUAL=", visual->class);
  147.     
  148.     putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy)));
  149.  
  150.     putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy)));
  151.     putidef(line, " -DSCR_HEIGHT=", 
  152.         HeightOfScreen(DefaultScreenOfDisplay(dpy)));
  153.  
  154.     /* put the dir where the menu is being read from to the
  155.      * search path */
  156.     if (path) {
  157.     tmp = wstrdup(path);
  158.     buf = strchr(tmp+1, ' ');
  159.     if (buf) {
  160.         *buf = 0;
  161.     }
  162.     buf = strrchr(tmp, '/');
  163.     if (buf) {
  164.         *buf = 0; /* trunc filename */
  165.         putdef(line, " -I", tmp);
  166.     }
  167.     free(tmp);
  168.     }
  169.  
  170.  
  171.     /* this should be done just once, but it works this way */
  172.     strcpy(buffer, DEF_CONFIG_PATHS);
  173.     buf = strtok(buffer, ":");
  174.  
  175.     do {
  176.       char fullpath[MAXLINE];
  177.  
  178.       if (buf[0]!='~') {
  179.     strcpy(fullpath, buf);
  180.       } else {
  181.     char * wgethomedir();
  182.     /* home is statically allocated. Don't free it! */
  183.     char *home = wgethomedir();
  184.     
  185.     strcpy(fullpath, home);
  186.     strcat(fullpath, &(buf[1]));
  187.       }
  188.  
  189.       putdef(line, " -I", fullpath);
  190.  
  191.     } while ((buf = strtok(NULL, ":"))!=NULL);
  192.     
  193. #undef arg
  194. #ifdef DEBUG
  195.     puts("CPP ARGS");
  196.     puts(line);
  197. #endif
  198.     return line;
  199. }
  200. #endif /* USECPP */
  201.  
  202.  
  203.  
  204.  
  205.  
  206. WWindow*
  207. NextToFocusAfter(WWindow *wwin)
  208. {
  209.     WWindow *tmp = wwin->prev;
  210.  
  211.     while (tmp) {
  212.     if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
  213.         return tmp;
  214.     }
  215.     tmp = tmp->prev;
  216.     }
  217.  
  218.     tmp = wwin;
  219.     /* start over from the beginning of the list */
  220.     while (tmp->next)
  221.     tmp = tmp->next;
  222.  
  223.     while (tmp && tmp != wwin) {
  224.     if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
  225.         return tmp;
  226.     }
  227.     tmp = tmp->prev;
  228.     }
  229.  
  230.     return wwin;
  231. }
  232.  
  233.  
  234. WWindow*
  235. NextToFocusBefore(WWindow *wwin)
  236. {
  237.     WWindow *tmp = wwin->next;
  238.  
  239.     while (tmp) {
  240.     if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
  241.         return tmp;
  242.     }
  243.     tmp = tmp->next;
  244.     }
  245.  
  246.     /* start over from the beginning of the list */
  247.     tmp = wwin;
  248.     while (tmp->prev)
  249.     tmp = tmp->prev;
  250.  
  251.     while (tmp && tmp != wwin) {
  252.     if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
  253.  
  254.         return tmp;
  255.     }
  256.     tmp = tmp->next;
  257.     }
  258.  
  259.     return wwin;
  260. }
  261.  
  262.  
  263. #if 0
  264. /*
  265.  * Is win2 below win1?
  266.  */
  267. static Bool
  268. isBelow(WWindow *win1, WWindow *win2)
  269. {
  270.     int i;
  271.     WCoreWindow *tmp;
  272.     
  273.     tmp = win1->frame->core->stacking->under;
  274.     while (tmp) {
  275.     if (tmp == win2->frame->core)
  276.         return True;
  277.     tmp = tmp->stacking->under;
  278.     }
  279.     
  280.     for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) {
  281.     tmp = win1->screen_ptr->stacking_list[i];
  282.     while (tmp) {
  283.         if (tmp == win2->frame->core)
  284.         return True;
  285.         tmp = tmp->stacking->under;
  286.     }
  287.     }
  288.     return True;
  289. }
  290. #endif
  291.  
  292.  
  293.  
  294. /*
  295.  *  XFetchName Wrapper
  296.  *
  297.  */
  298. Bool wFetchName(dpy, win, winname)
  299. Display *dpy;
  300. Window win;
  301. char **winname;
  302. {
  303.     XTextProperty text_prop;
  304.     char **list;
  305.     int num;
  306.  
  307.     if (XGetWMName(dpy, win, &text_prop)) {
  308.     if (text_prop.value && text_prop.nitems > 0) {
  309.         if (text_prop.encoding == XA_STRING) {
  310.         *winname = wstrdup((char *)text_prop.value);
  311.         XFree(text_prop.value);
  312.         } else {
  313.         text_prop.nitems = strlen((char *)text_prop.value);
  314.         if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
  315.             Success && num > 0 && *list) {
  316.             XFree(text_prop.value);
  317.             *winname = wstrdup(*list);
  318.             XFreeStringList(list);
  319.         } else {
  320.             *winname = wstrdup((char *)text_prop.value);
  321.             XFree(text_prop.value);
  322.         }
  323.         }
  324.     } else {
  325.         /* the title is set, but it was set to none */
  326.         *winname = wstrdup("");
  327.     }
  328.     return True;
  329.     } else {
  330.     /* the hint is probably not set */
  331.     *winname = NULL;
  332.     
  333.     return False;
  334.     }
  335. }
  336.  
  337. /*
  338.  *  XGetIconName Wrapper
  339.  *
  340.  */
  341.  
  342. Bool wGetIconName(dpy, win, iconname)
  343. Display *dpy;
  344. Window win;
  345. char **iconname;
  346. {
  347.     XTextProperty text_prop;
  348.     char **list;
  349.     int num;
  350.     
  351.     if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value
  352.     && text_prop.nitems > 0) {
  353.     if (text_prop.encoding == XA_STRING)
  354.         *iconname = (char *)text_prop.value;
  355.     else {
  356.         text_prop.nitems = strlen((char *)text_prop.value);
  357.         if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >=
  358.         Success && num > 0 && *list) {
  359.         XFree(text_prop.value);
  360.         *iconname = wstrdup(*list);
  361.         XFreeStringList(list);
  362.         } else
  363.         *iconname = (char *)text_prop.value;
  364.     }
  365.     return True;
  366.     }
  367.     *iconname = NULL;
  368.     return False;
  369. }
  370.  
  371.  
  372. static void 
  373. eatExpose()
  374. {
  375.     XEvent event, foo;
  376.     
  377.     /* compress all expose events into a single one */
  378.     
  379.     if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
  380.     /* ignore other exposure events for this window */
  381.     while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask,
  382.                    &foo));
  383.     /* eat exposes for other windows */
  384.     eatExpose();
  385.     
  386.     event.xexpose.count = 0;
  387.     XPutBackEvent(dpy, &event);
  388.     }
  389. }
  390.  
  391.  
  392. void
  393. SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y)
  394. {
  395.     time_t time0 = time(NULL);
  396.     float dx, dy, x=from_x, y=from_y, sx, sy, px, py;
  397.     int dx_is_bigger=0;
  398.  
  399.     /* animation parameters */
  400.     static struct {
  401.     int delay;
  402.     int steps;
  403.     int slowdown;
  404.     } apars[5] = {
  405.     {ICON_SLIDE_DELAY_UF, ICON_SLIDE_STEPS_UF, ICON_SLIDE_SLOWDOWN_UF},
  406.     {ICON_SLIDE_DELAY_F, ICON_SLIDE_STEPS_F, ICON_SLIDE_SLOWDOWN_F},
  407.     {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M},
  408.     {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S},
  409.     {ICON_SLIDE_DELAY_U, ICON_SLIDE_STEPS_U, ICON_SLIDE_SLOWDOWN_U}};
  410.     
  411.     
  412.  
  413.     dx = (float)(to_x-from_x);
  414.     dy = (float)(to_y-from_y);
  415.     sx = (dx == 0 ? 0 : fabs(dx)/dx);
  416.     sy = (dy == 0 ? 0 : fabs(dy)/dy);
  417.  
  418.     if (fabs(dx) > fabs(dy)) {
  419.         dx_is_bigger = 1;
  420.     }
  421.  
  422.     if (dx_is_bigger) {
  423.         px = dx / apars[(int)wPreferences.icon_slide_speed].slowdown;
  424.         if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
  425.             px = apars[(int)wPreferences.icon_slide_speed].steps;
  426.         else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
  427.             px = -apars[(int)wPreferences.icon_slide_speed].steps;
  428.         py = (sx == 0 ? 0 : px*dy/dx);
  429.     } else {
  430.         py = dy / apars[(int)wPreferences.icon_slide_speed].slowdown;
  431.         if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
  432.             py = apars[(int)wPreferences.icon_slide_speed].steps;
  433.         else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
  434.             py = -apars[(int)wPreferences.icon_slide_speed].steps;
  435.         px = (sy == 0 ? 0 : py*dx/dy);
  436.     }
  437.  
  438.     while (x != to_x || y != to_y) {
  439.     x += px;
  440.         y += py;
  441.         if ((px<0 && (int)x < to_x) || (px>0 && (int)x > to_x))
  442.             x = (float)to_x;
  443.         if ((py<0 && (int)y < to_y) || (py>0 && (int)y > to_y))
  444.             y = (float)to_y;
  445.  
  446.         if (dx_is_bigger) {
  447.             px = px * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
  448.             if (px < apars[(int)wPreferences.icon_slide_speed].steps && px > 0)
  449.                 px = apars[(int)wPreferences.icon_slide_speed].steps;
  450.             else if (px > -apars[(int)wPreferences.icon_slide_speed].steps && px < 0)
  451.                 px = -apars[(int)wPreferences.icon_slide_speed].steps;
  452.             py = (sx == 0 ? 0 : px*dy/dx);
  453.         } else {
  454.             py = py * (1.0 - 1/(float)apars[(int)wPreferences.icon_slide_speed].slowdown);
  455.             if (py < apars[(int)wPreferences.icon_slide_speed].steps && py > 0)
  456.                 py = apars[(int)wPreferences.icon_slide_speed].steps;
  457.             else if (py > -apars[(int)wPreferences.icon_slide_speed].steps && py < 0)
  458.                 py = -apars[(int)wPreferences.icon_slide_speed].steps;
  459.             px = (sy == 0 ? 0 : py*dx/dy);
  460.         }
  461.  
  462.         XMoveWindow(dpy, win, (int)x, (int)y);
  463.         XFlush(dpy);
  464.         if (apars[(int)wPreferences.icon_slide_speed].delay > 0) {
  465.             wusleep(apars[(int)wPreferences.icon_slide_speed].delay*1000L);
  466.         }
  467.     if (time(NULL) - time0 > MAX_ANIMATION_TIME)
  468.         break;
  469.     }
  470.     XMoveWindow(dpy, win, to_x, to_y);
  471.  
  472.     XSync(dpy, 0);
  473.     /* compress expose events */
  474.     eatExpose();
  475. }
  476.  
  477.  
  478. char*
  479. ShrinkString(WMFont *font, char *string, int width)
  480. {
  481.     int w, w1=0;
  482.     int p;
  483.     char *pos;
  484.     char *text;
  485.     int p1, p2, t;
  486.  
  487.     if (wPreferences.multi_byte_text)
  488.     return wstrdup(string);
  489.  
  490.     p = strlen(string);
  491.     w = WMWidthOfString(font, string, p);
  492.     text = wmalloc(strlen(string)+8);
  493.     strcpy(text, string);
  494.     if (w<=width)
  495.       return text;
  496.  
  497.     pos = strchr(text, ' ');
  498.     if (!pos)
  499.       pos = strchr(text, ':');
  500.  
  501.     if (pos) {
  502.     *pos = 0;
  503.     p = strlen(text);
  504.     w1 = WMWidthOfString(font, text, p);
  505.     if (w1 > width) {
  506.         w1 = 0;
  507.         p = 0;
  508.         *pos = ' ';
  509.         *text = 0;
  510.     } else {
  511.         *pos = 0;
  512.         width -= w1;
  513.         p++;
  514.     }
  515.     string += p;
  516.     p=strlen(string);
  517.     } else {
  518.     *text=0;
  519.     }
  520.     strcat(text, "...");
  521.     width -= WMWidthOfString(font, "...", 3);
  522.     
  523.     pos = string;
  524.     p1=0;
  525.     p2=p;
  526.     t = (p2-p1)/2;
  527.     while (p2>p1 && p1!=t) {
  528.     w = WMWidthOfString(font, &string[p-t], t);
  529.     if (w>width) {
  530.         p2 = t;
  531.         t = p1+(p2-p1)/2;
  532.     } else if (w<width) {
  533.         p1 = t;
  534.         t = p1+(p2-p1)/2;
  535.     } else 
  536.       p2=p1=t;
  537.     }
  538.     strcat(text, &string[p-p1]);
  539.  
  540.     return text;
  541. }
  542.  
  543.  
  544. char*
  545. FindImage(char *paths, char *file)
  546. {
  547.     char *tmp, *path;
  548.  
  549.     tmp = strrchr(file, ':');
  550.     if (tmp) {
  551.     *tmp = 0;
  552.     path = wfindfile(paths, file);
  553.     *tmp = ':';
  554.     }
  555.     if (!tmp || !path) {
  556.     path = wfindfile(paths, file);
  557.     }
  558.  
  559.     return path;
  560. }
  561.  
  562.  
  563. char*
  564. FlattenStringList(char **list, int count)
  565. {
  566.     int i, j;
  567.     char *flat_string, *wspace;
  568.  
  569.     j = 0;
  570.     for (i=0; i<count; i++) {
  571.         if (list[i]!=NULL && list[i][0]!=0) {
  572.             j += strlen(list[i]);
  573.             if (strpbrk(list[i], " \t"))
  574.                 j += 2;
  575.         }
  576.     }
  577.     
  578.     flat_string = malloc(j+count+1);
  579.     if (!flat_string) {
  580.     return NULL;
  581.     }
  582.  
  583.     *flat_string = 0;
  584.     for (i=0; i<count; i++) {
  585.     if (list[i]!=NULL && list[i][0]!=0) {
  586.         if (i>0)
  587.         strcat(flat_string, " ");
  588.             wspace = strpbrk(list[i], " \t");
  589.             if (wspace)
  590.                 strcat(flat_string, "\"");
  591.         strcat(flat_string, list[i]);
  592.             if (wspace)
  593.                 strcat(flat_string, "\"");
  594.     }
  595.     }
  596.  
  597.     return flat_string;
  598. }
  599.  
  600.  
  601.  
  602. /*
  603.  *----------------------------------------------------------------------
  604.  * ParseCommand --
  605.  *     Divides a command line into a argv/argc pair.
  606.  *---------------------------------------------------------------------- 
  607.  */
  608. #define PRC_ALPHA    0
  609. #define PRC_BLANK    1
  610. #define PRC_ESCAPE    2
  611. #define PRC_DQUOTE    3
  612. #define PRC_EOS        4
  613. #define PRC_SQUOTE    5
  614.  
  615. typedef struct {
  616.     short nstate;
  617.     short output;
  618. } DFA;
  619.  
  620.  
  621. static DFA mtable[9][6] = {
  622.     {{3,1},{0,0},{4,0},{1,0},{8,0},{6,0}},
  623.     {{1,1},{1,1},{2,0},{3,0},{5,0},{1,1}},
  624.     {{1,1},{1,1},{1,1},{1,1},{5,0},{1,1}},
  625.     {{3,1},{5,0},{4,0},{1,0},{5,0},{6,0}},
  626.     {{3,1},{3,1},{3,1},{3,1},{5,0},{3,1}},
  627.     {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
  628.     {{6,1},{6,1},{7,0},{6,1},{5,0},{3,0}},
  629.     {{6,1},{6,1},{6,1},{6,1},{5,0},{6,1}},
  630.     {{-1,-1},{0,0},{0,0},{0,0},{0,0},{0,0}}, /* final state */
  631. };
  632.  
  633. char*
  634. next_token(char *word, char **next)
  635. {
  636.     char *ptr;
  637.     char *ret, *t;
  638.     int state, ctype;
  639.  
  640.     t = ret = wmalloc(strlen(word)+1);
  641.     ptr = word;
  642.     
  643.     state = 0;
  644.     *t = 0;
  645.     while (1) {
  646.     if (*ptr==0) 
  647.         ctype = PRC_EOS;
  648.     else if (*ptr=='\\')
  649.         ctype = PRC_ESCAPE;
  650.     else if (*ptr=='"')
  651.         ctype = PRC_DQUOTE;
  652.     else if (*ptr=='\'')
  653.         ctype = PRC_SQUOTE;
  654.     else if (*ptr==' ' || *ptr=='\t')
  655.         ctype = PRC_BLANK;
  656.     else
  657.         ctype = PRC_ALPHA;
  658.  
  659.     if (mtable[state][ctype].output) {
  660.         *t = *ptr; t++;
  661.         *t = 0;
  662.     }
  663.     state = mtable[state][ctype].nstate;
  664.     ptr++;
  665.     if (mtable[state][0].output<0) {
  666.         break;
  667.     }
  668.     }
  669.  
  670.     if (*ret==0)
  671.     t = NULL;
  672.     else
  673.     t = wstrdup(ret);
  674.  
  675.     free(ret);
  676.     
  677.     if (ctype==PRC_EOS)
  678.     *next = NULL;
  679.     else
  680.     *next = ptr;
  681.     
  682.     return t;
  683. }
  684.  
  685.  
  686. void
  687. ParseCommand(char *command, char ***argv, int *argc)
  688. {
  689.     WMBag *bag = WMCreateBag(4);
  690.     char *token, *line;
  691.     int count, j;
  692.  
  693.     line = command;
  694.     do {
  695.     token = next_token(line, &line);
  696.     if (token) {
  697.         WMPutInBag(bag, token);
  698.     }
  699.     } while (token!=NULL && line!=NULL);
  700.  
  701.     count = WMGetBagItemCount(bag);
  702.     *argv = wmalloc(sizeof(char*)*count);
  703.     for (j = 0; j < count; j++) {
  704.     (*argv)[j] = WMGetFromBag(bag, j);
  705.     }
  706.     *argc = count;
  707.  
  708.     WMFreeBag(bag);
  709. }
  710.  
  711. #if 0
  712. static void
  713. timeup(void *foo)
  714. {
  715.     *(int*)foo=1;
  716. }
  717. #endif
  718. static char*
  719. getselection(WScreen *scr)
  720. {
  721.     char *tmp;
  722.     extern char *W_GetTextSelection(); /* in WINGs */
  723.     
  724.     tmp = W_GetTextSelection(scr->wmscreen, XA_PRIMARY);
  725.     if (!tmp)
  726.     tmp = W_GetTextSelection(scr->wmscreen, XA_CUT_BUFFER0);
  727.     return tmp;
  728.  
  729. #if 0
  730.     XEvent event;
  731.     int timeover=0;
  732.     WMHandlerID *id;
  733.     
  734. #ifdef DEBUG
  735.     puts("getting selection");
  736. #endif
  737.     RequestSelection(dpy, scr->no_focus_win, LastTimestamp);
  738.     /* timeout on 1 sec. */
  739.     id = WMAddTimerHandler(1000, timeup, &timeover);
  740.     while (!timeover) {
  741.     WMNextEvent(dpy, &event);
  742.     if (event.type == SelectionNotify 
  743.         && event.xany.window==scr->no_focus_win) {
  744.         WMDeleteTimerHandler(id);
  745. #ifdef DEBUG
  746.         puts("selection ok");
  747. #endif
  748.         return GetSelection(dpy, scr->no_focus_win);
  749.     } else {
  750.         WMHandleEvent(&event);
  751.     }
  752.     }
  753.     wwarning(_("selection timed-out"));
  754.     return NULL;
  755. #endif
  756. }
  757.  
  758.  
  759. static char*
  760. getuserinput(WScreen *scr, char *line, int *ptr)
  761. {
  762.     char *ret;
  763.     char *title;
  764.     char *prompt;
  765.     int j, state;
  766.     int begin = 0;
  767.     char tbuffer[256], pbuffer[256];
  768.  
  769.     title = _("Program Arguments");
  770.     prompt = _("Enter command arguments:");
  771.     ret = NULL;
  772.  
  773. #define _STARTING 0
  774. #define _TITLE 1
  775. #define _PROMPT 2
  776. #define _DONE 3
  777.  
  778.     state = _STARTING;
  779.     j = 0;
  780.     for (; line[*ptr]!=0 && state!=_DONE; (*ptr)++) {
  781.     switch (state) {
  782.      case _STARTING:
  783.         if (line[*ptr]=='(') {
  784.         state = _TITLE;
  785.         begin = *ptr+1;
  786.         } else {
  787.         state = _DONE;
  788.         }
  789.         break;
  790.  
  791.      case _TITLE:
  792.         if (j <= 0 && line[*ptr]==',') {
  793.  
  794.         j = 0;
  795.         if (*ptr > begin) {
  796.             strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
  797.             tbuffer[WMIN(*ptr-begin, 255)] = 0;
  798.             title = (char*)tbuffer;
  799.         }
  800.         begin = *ptr+1;
  801.         state = _PROMPT;
  802.  
  803.         } else if (j <= 0 && line[*ptr]==')') {
  804.  
  805.         if (*ptr > begin) {
  806.             strncpy(tbuffer, &line[begin], WMIN(*ptr-begin, 255));
  807.             tbuffer[WMIN(*ptr-begin, 255)] = 0;
  808.             title = (char*)tbuffer;
  809.         }
  810.         state = _DONE;
  811.  
  812.         } else if (line[*ptr]=='(') {
  813.         j++;
  814.         } else if (line[*ptr]==')') {
  815.         j--;
  816.         }
  817.  
  818.         break;
  819.  
  820.      case _PROMPT:
  821.         if (line[*ptr]==')' && j==0) {
  822.  
  823.         if (*ptr-begin > 1) {
  824.             strncpy(pbuffer, &line[begin], WMIN(*ptr-begin, 255));
  825.             pbuffer[WMIN(*ptr-begin, 255)] = 0;
  826.             prompt = (char*)pbuffer;
  827.         }
  828.         state = _DONE;
  829.         } else if (line[*ptr]=='(')
  830.             j++;
  831.         else if (line[*ptr]==')')
  832.         j--;
  833.         break;
  834.     }
  835.     }
  836.     (*ptr)--;
  837. #undef _STARTING
  838. #undef _TITLE
  839. #undef _PROMPT
  840. #undef _DONE
  841.  
  842.     if (!wInputDialog(scr, title, prompt, &ret))
  843.     return NULL;
  844.     else
  845.     return ret;
  846. }
  847.  
  848.  
  849. #ifdef OFFIX_DND
  850. static char*
  851. get_dnd_selection(WScreen *scr)
  852. {
  853.     XTextProperty text_ret;
  854.     int result;
  855.     char **list;
  856.     char *flat_string;
  857.     int count;
  858.     
  859.     result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION);
  860.     
  861.     if (result==0 || text_ret.value==NULL || text_ret.encoding==None
  862.     || text_ret.format==0 || text_ret.nitems == 0) {
  863.     wwarning(_("unable to get dropped data from DND drop"));
  864.     return NULL;
  865.     }
  866.     
  867.     XTextPropertyToStringList(&text_ret, &list, &count);
  868.     
  869.     if (!list || count<1) {
  870.     XFree(text_ret.value);
  871.     wwarning(_("error getting dropped data from DND drop"));
  872.     return NULL;
  873.     }
  874.  
  875.     flat_string = FlattenStringList(list, count);
  876.     if (!flat_string) {
  877.     wwarning(_("out of memory while getting data from DND drop"));
  878.     }
  879.     
  880.     XFreeStringList(list);
  881.     XFree(text_ret.value);
  882.     return flat_string;
  883. }
  884. #endif /* OFFIX_DND */
  885.  
  886.  
  887. #define S_NORMAL 0
  888. #define S_ESCAPE 1
  889. #define S_OPTION 2
  890.  
  891. /* 
  892.  * state        input   new-state    output
  893.  * NORMAL    %    OPTION        <nil>
  894.  * NORMAL    \    ESCAPE        <nil>
  895.  * NORMAL    etc.    NORMAL        <input>
  896.  * ESCAPE    any    NORMAL        <input>
  897.  * OPTION    s    NORMAL        <selection buffer>
  898.  * OPTION    w    NORMAL        <selected window id>
  899.  * OPTION    a    NORMAL        <input text>
  900.  * OPTION    d    NORMAL        <OffiX DND selection object>
  901.  * OPTION    W    NORMAL        <current workspace>
  902.  * OPTION    etc.    NORMAL        %<input>
  903.  */
  904. #define TMPBUFSIZE 64
  905. char*
  906. ExpandOptions(WScreen *scr, char *cmdline)
  907. {
  908.     int ptr, optr, state, len, olen;
  909.     char *out, *nout;
  910.     char *selection=NULL;
  911.     char *user_input=NULL;
  912. #if defined(OFFIX_DND) || defined(XDND)
  913.     char *dropped_thing=NULL;
  914. #endif
  915.     char tmpbuf[TMPBUFSIZE];
  916.     int slen;
  917.  
  918.     len = strlen(cmdline);
  919.     olen = len+1;
  920.     out = malloc(olen);
  921.     if (!out) {
  922.     wwarning(_("out of memory during expansion of \"%s\""));
  923.     return NULL;
  924.     }
  925.     *out = 0;
  926.     ptr = 0;                    /* input line pointer */
  927.     optr = 0;                   /* output line pointer */
  928.     state = S_NORMAL;
  929.     while (ptr < len) {
  930.     switch (state) {
  931.      case S_NORMAL:
  932.         switch (cmdline[ptr]) {
  933.          case '\\':
  934.         state = S_ESCAPE;
  935.         break;
  936.          case '%':
  937.         state = S_OPTION;
  938.         break;
  939.          default:
  940.         state = S_NORMAL;
  941.         out[optr++]=cmdline[ptr];
  942.         break;
  943.         }
  944.         break;
  945.      case S_ESCAPE:
  946.         switch (cmdline[ptr]) {
  947.          case 'n':
  948.         out[optr++]=10;
  949.         break;
  950.         
  951.          case 'r':
  952.         out[optr++]=13;
  953.         break;
  954.         
  955.          case 't':
  956.         out[optr++]=9;
  957.         break;
  958.         
  959.          default:
  960.         out[optr++]=cmdline[ptr];
  961.         }
  962.         state = S_NORMAL;
  963.         break;
  964.      case S_OPTION:
  965.         state = S_NORMAL;
  966.         switch (cmdline[ptr]) {
  967.          case 'w':
  968.         if (scr->focused_window
  969.             && scr->focused_window->flags.focused) {
  970.             sprintf(tmpbuf, "0x%x", 
  971.                 (unsigned int)scr->focused_window->client_win);
  972.             slen = strlen(tmpbuf);
  973.             olen += slen;
  974.             nout = realloc(out,olen);
  975.             if (!nout) {
  976.             wwarning(_("out of memory during expansion of \"%w\""));
  977.             goto error;
  978.             }
  979.             out = nout;
  980.             strcat(out,tmpbuf);
  981.             optr+=slen;
  982.         } else {
  983.             out[optr++]=' ';
  984.         }
  985.         break;
  986.         
  987.          case 'W':
  988.         sprintf(tmpbuf, "0x%x", 
  989.             (unsigned int)scr->current_workspace + 1);
  990.         slen = strlen(tmpbuf);
  991.         olen += slen;
  992.         nout = realloc(out,olen);
  993.         if (!nout) {
  994.             wwarning(_("out of memory during expansion of \"%W\""));
  995.             goto error;
  996.         }
  997.         out = nout;
  998.         strcat(out,tmpbuf);
  999.         optr+=slen;
  1000.         break;
  1001.         
  1002.          case 'a':
  1003.         ptr++;
  1004.         user_input = getuserinput(scr, cmdline, &ptr); 
  1005.         if (user_input) {
  1006.             slen = strlen(user_input);
  1007.             olen += slen;
  1008.             nout = realloc(out,olen);
  1009.             if (!nout) {
  1010.             wwarning(_("out of memory during expansion of \"%a\""));
  1011.             goto error;
  1012.             }
  1013.             out = nout;
  1014.             strcat(out,user_input);
  1015.             optr+=slen;
  1016.         } else {
  1017.             /* Not an error, but user has Canceled the dialog box.
  1018.              * This will make the command to not be performed. */
  1019.             goto error;
  1020.         }
  1021.         break;
  1022.  
  1023. #if defined(OFFIX_DND) || defined(XDND)
  1024.          case 'd':
  1025. #ifdef XDND
  1026.         if(scr->xdestring) {
  1027.             dropped_thing = wstrdup(scr->xdestring);
  1028.         }
  1029. #endif
  1030.         if (!dropped_thing) {
  1031.             dropped_thing = get_dnd_selection(scr);
  1032.         }
  1033.         if (!dropped_thing) {
  1034.             scr->flags.dnd_data_convertion_status = 1;
  1035.             goto error;
  1036.         }
  1037.         slen = strlen(dropped_thing);
  1038.         olen += slen;
  1039.         nout = realloc(out,olen);
  1040.         if (!nout) {
  1041.             wwarning(_("out of memory during expansion of \"%d\""));
  1042.             goto error;
  1043.         }
  1044.         out = nout;
  1045.         strcat(out,dropped_thing);
  1046.         optr+=slen;
  1047.         break;
  1048. #endif /* OFFIX_DND */
  1049.         
  1050.          case 's':
  1051.         if (!selection) {
  1052.             selection = getselection(scr);
  1053.         }
  1054.         if (!selection) {
  1055.             wwarning(_("selection not available"));
  1056.             goto error;
  1057.         }
  1058.         slen = strlen(selection);
  1059.         olen += slen;
  1060.         nout = realloc(out,olen);
  1061.         if (!nout) {
  1062.             wwarning(_("out of memory during expansion of \"%s\""));
  1063.             goto error;
  1064.         }
  1065.         out = nout;
  1066.         strcat(out,selection);
  1067.         optr+=slen;
  1068.         break;
  1069.          default:
  1070.         out[optr++]='%';
  1071.         out[optr++]=cmdline[ptr];
  1072.         }
  1073.         break;
  1074.     }
  1075.     out[optr]=0;
  1076.     ptr++;
  1077.     }
  1078.     if (selection)
  1079.       XFree(selection);
  1080.     return out;
  1081.     
  1082.     error:
  1083.     free(out);
  1084.     if (selection)
  1085.       XFree(selection);
  1086.     return NULL;
  1087. }
  1088.  
  1089.  
  1090. /* We don't care for upper/lower case in comparing the keys; so we
  1091.    have to define our own comparison function here */
  1092. BOOL
  1093. StringCompareHook(proplist_t pl1, proplist_t pl2)
  1094. {
  1095.     char *str1, *str2;
  1096.  
  1097.     str1 = PLGetString(pl1);
  1098.     str2 = PLGetString(pl2);
  1099.  
  1100.     if (strcasecmp(str1, str2)==0)
  1101.       return YES;
  1102.     else
  1103.       return NO;
  1104. }
  1105.  
  1106.  
  1107. /* feof doesn't seem to work on pipes */
  1108. int
  1109. IsEof(FILE * stream)
  1110. {
  1111.     static struct stat stinfo;
  1112.  
  1113.     fstat(fileno(stream), &stinfo);
  1114.     return ((S_ISFIFO(stinfo.st_dev) && stinfo.st_size == 0) || 
  1115.             feof(stream));
  1116. }
  1117.  
  1118.  
  1119. void
  1120. ParseWindowName(proplist_t value, char **winstance, char **wclass, char *where)
  1121. {
  1122.     char *name;
  1123.  
  1124.     *winstance = *wclass = NULL;
  1125.  
  1126.     if (!PLIsString(value)) {
  1127.     wwarning(_("bad window name value in %s state info"), where);
  1128.     return;
  1129.     }
  1130.  
  1131.     name = PLGetString(value);
  1132.     if (!name || strlen(name)==0) {
  1133.     wwarning(_("bad window name value in %s state info"), where);
  1134.     return;
  1135.     }
  1136.  
  1137.     UnescapeWM_CLASS(name, winstance, wclass);
  1138. }
  1139.  
  1140.  
  1141. #if 0
  1142. static char*
  1143. keysymToString(KeySym keysym, unsigned int state)
  1144. {
  1145.     XKeyEvent kev;
  1146.     char *buf = wmalloc(20);
  1147.     int count;
  1148.  
  1149.     kev.display = dpy;
  1150.     kev.type = KeyPress;
  1151.     kev.send_event = False;
  1152.     kev.window = DefaultRootWindow(dpy);
  1153.     kev.root = DefaultRootWindow(dpy);
  1154.     kev.same_screen = True;
  1155.     kev.subwindow = kev.root;
  1156.     kev.serial = 0x12344321;
  1157.     kev.time = CurrentTime;
  1158.     kev.state = state;
  1159.     kev.keycode = XKeysymToKeycode(dpy, keysym);
  1160.     count = XLookupString(&kev, buf, 19, NULL, NULL);
  1161.     buf[count] = 0;
  1162.  
  1163.     return buf;
  1164. }
  1165. #endif
  1166.  
  1167. static char *
  1168. appendrealloc(char *a, char *b)
  1169. {
  1170.     if (a == NULL)
  1171.     return wstrdup(b);
  1172.     else {
  1173.     char *c = wstrappend(a, b);
  1174.     free(a);
  1175.     return c;
  1176.     }
  1177. }
  1178.  
  1179.  
  1180. char*
  1181. GetShortcutString(char *text)
  1182. {
  1183.     char *buffer = NULL;
  1184.     char *k;
  1185.     int modmask = 0;
  1186. /*    KeySym ksym;*/
  1187.     int control = 0;
  1188.     char *tmp;
  1189.     
  1190.     tmp = text = wstrdup(text);
  1191.  
  1192.     /* get modifiers */
  1193.     while ((k = strchr(text, '+'))!=NULL) {
  1194.     int mod;
  1195.     
  1196.     *k = 0;
  1197.     mod = wXModifierFromKey(text);
  1198.     if (mod<0) {
  1199.         return wstrdup("bug");
  1200.     }
  1201.         
  1202.     modmask |= mod;
  1203.     
  1204.     if (strcasecmp(text, "Meta")==0) {
  1205.         buffer = appendrealloc(buffer, "M+");
  1206.     } else if (strcasecmp(text, "Alt")==0) {
  1207.         buffer = appendrealloc(buffer, "A+");
  1208.     } else if (strcasecmp(text, "Shift")==0) {
  1209.         buffer = appendrealloc(buffer, "Sh+");
  1210.     } else if (strcasecmp(text, "Mod1")==0) {
  1211.         buffer = appendrealloc(buffer, "M1+"); 
  1212.     } else if (strcasecmp(text, "Mod2")==0) {
  1213.         buffer = appendrealloc(buffer, "M2+"); 
  1214.     } else if (strcasecmp(text, "Mod3")==0) {
  1215.         buffer = appendrealloc(buffer, "M3+");
  1216.     } else if (strcasecmp(text, "Mod4")==0) {
  1217.         buffer = appendrealloc(buffer, "M4+"); 
  1218.     } else if (strcasecmp(text, "Mod5")==0) {
  1219.         buffer = appendrealloc(buffer, "M5+"); 
  1220.     } else if (strcasecmp(text, "Control")==0) {
  1221.         control = 1;
  1222.     } else {
  1223.         buffer = appendrealloc(buffer, text);
  1224.     }
  1225.     text = k+1;
  1226.     }
  1227.  
  1228.     if (control) {
  1229.     buffer = appendrealloc(buffer, "^");
  1230.     }
  1231.     buffer = appendrealloc(buffer, text);
  1232.     
  1233.     /* get key */
  1234. /*    ksym = XStringToKeysym(text);
  1235.     tmp = keysymToString(ksym, modmask);
  1236.     puts(tmp);
  1237.     buffer = wstrappend(buffer, tmp);
  1238. */
  1239.     free(tmp);
  1240.  
  1241.     return buffer;
  1242. }
  1243.  
  1244.  
  1245. char*
  1246. EscapeWM_CLASS(char *name, char *class)
  1247. {
  1248.     char *ret;
  1249.     char *ename = NULL, *eclass = NULL;
  1250.     int i, j, l;
  1251.  
  1252.     if (!name && !class)
  1253.     return NULL;
  1254.  
  1255.     if (name) {
  1256.     l = strlen(name);
  1257.     ename = wmalloc(l*2);
  1258.     j = 0;
  1259.     for (i=0; i<l; i++) {
  1260.         if (name[i]=='\\') {
  1261.         ename[j++] = '\\';
  1262.         } else if (name[i]=='.') {
  1263.         ename[j++] = '\\';
  1264.         }
  1265.         ename[j++] = name[i];
  1266.     }
  1267.     ename[j] = 0;
  1268.     }
  1269.     if (class) {
  1270.     l = strlen(class);
  1271.     eclass = wmalloc(l*2);
  1272.     j = 0;
  1273.     for (i=0; i<l; i++) {
  1274.         if (class[i]=='\\') {
  1275.         eclass[j++] = '\\';
  1276.         } else if (class[i]=='.') {
  1277.         eclass[j++] = '\\';
  1278.         }
  1279.         eclass[j++] = class[i];
  1280.     }
  1281.     eclass[j] = 0;
  1282.     }
  1283.  
  1284.     if (ename && eclass) {
  1285.     ret = wmalloc(strlen(ename)+strlen(eclass)+4);
  1286.     sprintf(ret, "%s.%s", ename, eclass);
  1287.     free(ename);
  1288.     free(eclass);
  1289.     } else if (ename) {
  1290.     ret = wstrdup(ename);
  1291.     free(ename);
  1292.     } else {
  1293.     ret = wstrdup(eclass);
  1294.     free(eclass);
  1295.     }
  1296.  
  1297.     return ret;
  1298. }
  1299.  
  1300.  
  1301. void
  1302. UnescapeWM_CLASS(char *str, char **name, char **class)
  1303. {
  1304.     int i, j, k, dot;
  1305.     Bool esc;
  1306.  
  1307.     j = strlen(str);
  1308.     *name = wmalloc(j);
  1309.     **name = 0;
  1310.     *class = wmalloc(j);
  1311.     **class = 0;
  1312.  
  1313.     /* separate string in 2 parts */
  1314.     esc = False;
  1315.     dot = 0;
  1316.     for (i = 0; i < j; i++) {
  1317.     if (!esc) {
  1318.         if (str[i]=='\\') {
  1319.         esc = True;
  1320.         } else if (str[i]=='.') {
  1321.         dot = i;
  1322.         break;
  1323.         }
  1324.     } else {
  1325.         esc = False;
  1326.     }
  1327.     }
  1328.  
  1329.     /* unescape strings */
  1330.     esc = False;
  1331.     k = 0;
  1332.     for (i = 0; i < dot; i++) {
  1333.     if (!esc) {
  1334.         if (str[i]=='\\') {
  1335.         esc = True;
  1336.         } else {
  1337.         (*name)[k++] = str[i];
  1338.         }
  1339.     } else {
  1340.         (*name)[k++] = str[i];
  1341.         esc = False;
  1342.     }
  1343.     }
  1344.     (*name)[k] = 0;
  1345.  
  1346.     esc = False;
  1347.     k = 0;
  1348.     for (i = dot+1; i<j; i++) {
  1349.     if (!esc) {
  1350.         if (str[i]=='\\') {
  1351.         esc = True;
  1352.         } else {
  1353.         (*class)[k++] = str[i];
  1354.         }
  1355.     } else {
  1356.         esc = False;
  1357.     }
  1358.     }
  1359.     (*class)[k] = 0;
  1360.     
  1361.     if (!*name) {
  1362.     free(*name);
  1363.     *name = NULL;
  1364.     }
  1365.     if (!*class) {
  1366.     free(*class);
  1367.     *class = NULL;
  1368.     }
  1369. }
  1370.  
  1371.  
  1372.  
  1373. void
  1374. SendHelperMessage(WScreen *scr, char type, int workspace, char *msg)
  1375. {
  1376.     unsigned char *buffer;
  1377.     int len;
  1378.     int i;
  1379.     char buf[16];
  1380.  
  1381.     if (!scr->flags.backimage_helper_launched) {
  1382.     return;
  1383.     }
  1384.     
  1385.     len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ;
  1386.     buffer = wmalloc(len+5);
  1387.     sprintf(buf, "%4i", len);
  1388.     memcpy(buffer, buf, 4);
  1389.     buffer[4] = type;
  1390.     i = 5;
  1391.     if (workspace >= 0) {
  1392.     sprintf(buf, "%4i", workspace);
  1393.     memcpy(&buffer[i], buf, 4);
  1394.     i += 4;
  1395.     buffer[i] = 0;
  1396.     }
  1397.     if (msg)
  1398.     strcpy(&buffer[i], msg);
  1399.  
  1400.     if (write(scr->helper_fd, buffer, len+4) < 0) {
  1401.     wsyserror(_("could not send message to background image helper"));
  1402.     }
  1403.     free(buffer);
  1404. }
  1405.